import { Context } from 'koa'
import {
  delBatch,
  deleteRow,
  getPageQuery,
  insert,
  insertBatch,
  select,
  success,
  TSqlAndValues,
  update
} from '../utils'
import { devGit } from '../utils/git'
import path from 'path'
import { pool } from '../config/db'
import { secret_key } from '../config/secret'
import jwt from 'jsonwebtoken'
const fs = require('fs')
const fs2 = require('fs').promises

export class developController {
  // 复制服务器本地文件列表到数据库
  static async copyLocalFileToDatabase(ctx: Context) {
    const { system_id, branch_id } = ctx.request.body as any
    const [rows]: [any, any] = (await select('systems', { id: system_id })) as [any, any]
    const [rows2]: [any, any] = (await select('table_config', { systemId: system_id, branch_id })) as [any, any]
    const systemFolder = rows[0].code
    const nickname: string = ctx.request.headers.nickname as string
    const folderPath = path.join(`${process.env.DEV_GIT_FOLDER}-${nickname}`, `${systemFolder}`)
    const reg = new RegExp(`^(.*)(${systemFolder}.*)$`)
    const res = getAllFiles(folderPath).map((pathname) => {
      const filePath = pathname.replace(/\\/g, '/')
      console.warn('----- my data is filePath,1111 : ', filePath)
      const item = {
        pathname: filePath.replace(reg, '$2'),
        isSign: rows2.some((item: any) => filePath.endsWith(item.pathname))
      }
      return item
    })
    const [rows3]: [any, any] = (await select('work_files', { system_id, branch_id, nickname })) as [any, any]
    if (rows3.length) {
      await update('work_files', { system_id, branch_id, nickname }, { pathname_json: JSON.stringify(res) })
    } else {
      await insert('work_files', { system_id, branch_id, pathname_json: JSON.stringify(res), nickname })
    }
    ctx.body = success(ctx, res as any)
  }
  // 获取文件列表
  static async getFileList(ctx: Context) {
    const { system_id, branch_id, pathname } = ctx.request.body as any
    const { size, offset } = getPageQuery(ctx.request.body || {})
    const [rows]: [any, any] = (await select('work_files', {
      system_id,
      branch_id,
      nickname: ctx.request.headers.nickname
    })) as [any, any]
    if (rows.length) {
      let arr = JSON.parse(rows[0].pathname_json)
      if (pathname) {
        arr = arr.filter((item: { pathname: string }) => item.pathname === pathname)
      }
      ctx.body = success(ctx, { list: arr.slice(offset, offset + size), totalRows: arr.length })
    } else {
      ctx.body = success(ctx, { list: [], totalRows: 0 })
    }
  }
  // 文件打标
  static async setFileSign(ctx: Context) {
    const { data: arr, system_id, branch_id, pathname, nickname } = await getWorkFilesPathnames(ctx)
    arr.find((item: { pathname: string }) => item.pathname === pathname).isSign = true
    const connection = await pool.getConnection()
    try {
      await connection.beginTransaction()
      const { sql, values } = update(
        'work_files',
        { system_id, branch_id, nickname },
        { pathname_json: JSON.stringify(arr) },
        true
      ) as TSqlAndValues
      const { sql: sql2, values: values2 } = insert(
        'table_config',
        {
          systemId: system_id,
          name: '',
          pathname,
          branch_id,
          modifyTime: Date.now(),
          hasCode: 1,
          status: 3,
          modifier: nickname
        },
        true
      ) as TSqlAndValues
      await connection.execute(sql, values)
      await connection.execute(sql2, values2)
      await connection.commit()
    } finally {
      connection.release()
    }
    ctx.body = success(ctx, {})
  }
  // 批量文件打标
  static async batchSetFileSign(ctx: Context) {
    const { data: arr, system_id, branch_id, nickname } = await getWorkFilesPathnames(ctx)
    const { pathnames } = ctx.request.body as any
    arr.forEach((item: any) => pathnames.includes(item.pathname) && (item.isSign = true))
    const connection = await pool.getConnection()
    try {
      await connection.beginTransaction()
      const { sql, values } = update(
        'work_files',
        { system_id, branch_id, nickname },
        { pathname_json: JSON.stringify(arr) },
        true
      ) as TSqlAndValues
      const { sql: sql2, values: values2 } = insertBatch(
        'table_config',
        pathnames.map((pathname: string) => ({
          systemId: system_id,
          name: '',
          pathname,
          branch_id,
          modifyTime: Date.now(),
          hasCode: 1,
          status: 3,
          modifier: nickname
        })),
        true
      ) as TSqlAndValues
      await connection.execute(sql, values)
      await connection.query(sql2, values2)
      await connection.commit()
    } finally {
      connection.release()
    }
    ctx.body = success(ctx, {})
  }
  // 批量删除文件打标
  static async batchDelFileSign(ctx: Context) {
    const { data: arr, system_id, branch_id, nickname } = await getWorkFilesPathnames(ctx)
    const { pathnames } = ctx.request.body as any
    arr.forEach((item: any) => pathnames.includes(item.pathname) && (item.isSign = false))
    const connection = await pool.getConnection()
    try {
      await connection.beginTransaction()
      const { sql, values } = update(
        'work_files',
        { system_id, branch_id, nickname },
        { pathname_json: JSON.stringify(arr) },
        true
      ) as TSqlAndValues
      const { sql: sql2, values: values2 } = delBatch('table_config', pathnames, 'pathname', true) as TSqlAndValues
      await connection.execute(sql, values)
      await connection.query(sql2, values2)
      await connection.commit()
    } finally {
      connection.release()
    }
    ctx.body = success(ctx, {})
  }
  // 删除文件打标
  static async delFileSign(ctx: Context) {
    const { data: arr, system_id, branch_id, pathname, nickname } = await getWorkFilesPathnames(ctx)
    arr.find((item: { pathname: string }) => item.pathname === pathname).isSign = false
    const connection = await pool.getConnection()
    try {
      await connection.beginTransaction()
      const { sql, values } = update(
        'work_files',
        { system_id, branch_id, nickname },
        { pathname_json: JSON.stringify(arr) },
        true
      ) as TSqlAndValues
      const { sql: sql2, values: values2 } = deleteRow(
        'table_config',
        { systemId: system_id, branch_id, pathname },
        true
      ) as TSqlAndValues
      await connection.execute(sql, values)
      await connection.query(sql2, values2)
      await connection.commit()
    } finally {
      connection.release()
    }
    ctx.body = success(ctx, {})
  }
  // 删除文件
  static async delFile(ctx: Context) {
    const { data, system_id, branch_id, pathname, nickname } = await getWorkFilesPathnames(ctx)
    const arr = data.filter((item: { pathname: string }) => item.pathname !== pathname)
    await update('work_files', { system_id, branch_id, nickname }, { pathname_json: JSON.stringify(arr) })
    const filePath = path.join(`${process.env.DEV_GIT_FOLDER}-${nickname}`, pathname)
    await fs2.unlink(filePath)
    ctx.body = success(ctx, {})
  }
  // 标记文件为修改
  static async signFileModify(ctx: Context) {
    const { data: arr, system_id, branch_id, pathname, nickname } = await getWorkFilesPathnames(ctx)
    const ob = arr.find((item: { pathname: string }) => item.pathname === pathname)
    if (!ob) {
      arr.push({ pathname, isModify: true, isSign: true })
      await update('work_files', { system_id, branch_id, nickname }, { pathname_json: JSON.stringify(arr) })
    }
    if (ob && !ob.isModify) {
      ob.isModify = true
      await update('work_files', { system_id, branch_id, nickname }, { pathname_json: JSON.stringify(arr) })
    }
    ctx.body = success(ctx, {})
  }
  // git pull
  static async pull(ctx: Context) {
    const res = await devGit[ctx.request.headers.nickname as any].gitPull()
    ctx.body = success(ctx, res as any)
  }
  // git push
  static async push(ctx: Context) {
    const { branch_id } = ctx.request.body as any
    const res = await devGit[ctx.request.headers.nickname as any].gitPush()
    await update('branches', { id: branch_id }, { has_unpush_code: 0 })
    ctx.body = success(ctx, res as any)
  }
  // 获取文件代码
  static async getFileCode(ctx: Context) {
    const { pathname } = ctx.request.body as any
    const nickname: string = ctx.request.headers.nickname as string
    const filePath = path.join(`${process.env.DEV_GIT_FOLDER}-${nickname}`, pathname)
    const content = fs.readFileSync(filePath, 'utf-8')
    ctx.body = success(ctx, content)
  }
  // 新建、保存文件代码
  static async saveFileCode(ctx: Context) {
    const { pathname, code, branch_id } = ctx.request.body as any
    const [rows] = (await select('branches', { id: branch_id })) as [any, any]
    if (!rows[0].git_commit_msg) throw new Error('提交文案不存在，请先创建')
    const nickname: string = ctx.request.headers.nickname as string
    const filePath = path.join(`${process.env.DEV_GIT_FOLDER}-${nickname}`, pathname)
    const dirPath = path.dirname(filePath)
    if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true })
    fs.writeFileSync(filePath, code, 'utf-8')
    devGit[nickname].gitAddAll()
    const commitMsg = rows[0].git_commit_msg.replace(/^(.+?)(\*\d+)?$/, (_: string, content: string, num: string) => {
      if (!num) return content + '*1'
      return content + `*${Number(num.slice(1)) + 1}`
    })
    devGit[nickname].gitCommit(commitMsg)
    await update(
      'branches',
      { id: branch_id },
      { unpush_code_creator: nickname, has_unpush_code: 1, git_commit_msg: commitMsg }
    )
    ctx.body = success(ctx, {})
  }
  // 保存开发者
  static async saveDeveloper(ctx: Context) {
    const { branch_id } = ctx.request.body as any
    const nickname: string = ctx.request.headers.nickname as string
    const [rows] = (await select('branches', { id: branch_id })) as [any, any]
    const { coding_developer_token, coding_developer, unpush_code_creator, has_unpush_code } = rows[0] || {}
    const [rows2] = (await select('black_tokens', { token: coding_developer_token })) as [any, any]
    if (has_unpush_code && unpush_code_creator !== nickname) {
      throw new Error(`${unpush_code_creator}有代码未推送，请先联系他推送`)
    }
    try {
      if (coding_developer === nickname) {
        throw new Error('上一个开发是本人，可以进行开发')
      }
      if (rows2.length) {
        throw new Error('用户已退出，可以进行开发')
      }
      if (coding_developer_token) {
        jwt.verify(coding_developer_token || '', secret_key)
      } else {
        throw new Error('没有token')
      }
    } catch (error: any) {
      console.warn('----- my data is error.message: ', error)
      update(
        'branches',
        { id: branch_id },
        { coding_developer: nickname, coding_developer_token: ctx.cookies.get('token') }
      )
      return (ctx.body = success(ctx, {}))
    }
    throw new Error(`${coding_developer}正在开发`)
  }

  // 结束开发
  static async endDevelop(ctx: Context) {
    const { branch_id } = ctx.request.body as any
    const [rows]: [any, any] = (await select('branches', { id: branch_id })) as [any, any]
    if (rows?.[0]?.has_unpush_code) {
      throw new Error('当前有未推送的代码，请先推送代码')
    }
    await update('branches', { id: branch_id }, { coding_developer: '', coding_developer_token: '' })
    ctx.body = success(ctx, {})
  }

  // 获取git commit msg
  static async getCommitMsg(ctx: Context) {
    const { branch_id } = ctx.request.body as any
    const [rows]: [any, any] = (await select('branches', { id: branch_id })) as [any, any]
    ctx.body = success(ctx, { msg: rows[0].git_commit_msg })
  }

  // 更新git commit msg
  static async updateCommitMsg(ctx: Context) {
    const { branch_id, msg } = ctx.request.body as any
    await update('branches', { id: branch_id }, { git_commit_msg: msg })
    ctx.body = success(ctx, {})
  }
}

// 获取work_files对应的数据
const getWorkFilesPathnames = async (ctx: Context) => {
  const { system_id, branch_id, pathname } = ctx.request.body as any
  const nickname: string = ctx.request.headers.nickname as string
  const [rows]: [any, any] = (await select('work_files', { system_id, branch_id, nickname })) as [any, any]
  return { data: JSON.parse(rows[0].pathname_json), system_id, branch_id, pathname, nickname }
}

// 递归获取所有文件
const getAllFiles = (dirPath: string) => {
  if (!fs.existsSync(dirPath)) return []
  const files = fs.readdirSync(dirPath)
  let result: string[] = []

  files.forEach((file: string) => {
    const fullPath = path.join(dirPath, file)
    const stats = fs.statSync(fullPath)
    if (stats.isDirectory()) {
      // 如果是文件夹，递归调用
      result = result.concat(getAllFiles(fullPath))
    } else {
      // 如果是文件，直接加入结果
      result.push(fullPath)
    }
  })
  return result
}
